/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package project2;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Random;
import project1.*;

/**
 *
 * @author rr
 */
public class Solution {

    int[] assignments;
    boolean[] blockIsValid;
    boolean[] seqIsValid;

    int n = SetUp.getInstance().getLengthOfSchedule() * SetUp.getInstance().getNumberOfEmployees();
    private int seqError;
    private int blockError;

    public Solution(int[] assignments) {
        this.assignments = assignments;
    }

    public int[] getAssignments() {
        return assignments;
    }

    public void setAssignments(int[] assignments) {
        this.assignments = assignments;
    }

    private float countConstraintViolations() {

        this.seqIsValid = SetUp.getInstance().getSeqConstraint().check(this.assignments);
        this.blockIsValid = SetUp.getInstance().getBlockConstraint().check(this.assignments);

        //boolean [] validAssignments = curCon.check(this.assignments);
        // System.out.println(Arrays.toString(validAssignments));
        int countFalse = 0;

        for (boolean b : seqIsValid) {
            //if false: increment counter;
            if (!b) {
                countFalse++;
            }
        }
        this.seqError = countFalse;
        for (boolean b : blockIsValid) {
            //if false: increment counter;
            if (!b) {
                countFalse++;
            }
        }
        this.blockError = countFalse - seqError;
        return countFalse;
    }

    public float getError() {

        return this.countConstraintViolations();

    }

    public void randomize(int swaps) {
        Random r = new Random();
        for (int i = 0; i < swaps; i++) {
            int index1 = r.nextInt(assignments.length);
            int dayOfWeek = index1 % SetUp.getInstance().getLengthOfSchedule();

            int index2 = dayOfWeek + SetUp.getInstance().getLengthOfSchedule() * r.nextInt(SetUp.getInstance().getNumberOfEmployees());

            //swap
            int h = assignments[index1];
            assignments[index1] = assignments[index2];
            assignments[index2] = h;
        }
    }
    
    public void betterRandomize(int swaps) {
        this.countConstraintViolations();
        Random r = new Random();
        for (int i = 0; i < swaps; i++) {
            
            int index1 = 0;
            int dayOfWeek = 0;
            int index2 = 0;
            
            boolean invalidIndex = false;
            while(!invalidIndex)
            {
                index1 = r.nextInt(assignments.length);
                dayOfWeek = index1 % SetUp.getInstance().getLengthOfSchedule();
                index2 = dayOfWeek + SetUp.getInstance().getLengthOfSchedule() * r.nextInt(SetUp.getInstance().getNumberOfEmployees());

                if(!this.blockIsValid[index1] || !this.seqIsValid[index1]){
                    invalidIndex = true;
                }
                if(!this.blockIsValid[index2] || !this.seqIsValid[index2]){
                    invalidIndex = true;
                }
            }
            //swap
            int h = assignments[index1];
            assignments[index1] = assignments[index2];
            assignments[index2] = h;
            
        }
    }

      public int[] getOldAssignmentArray() {
        final int MIN_UNASSIGNED=3;        
        int[] assignmentArray = new int[this.n];
        boolean isOpenEnough;
        int range = 2;
        do {
            int[] unassignedCount = new int[SetUp.getInstance().getLengthOfSchedule()];
            for (int i = 0; i < unassignedCount.length; i++) { //init the array
                unassignedCount[i] = 0;
            }

            //set assignment array
            for (int i = 0; i < this.n; i++) {
                boolean isIndexOk = true;




                for (int j = -range; j <= range; j++) { //TODO: be more intelligent
                    if (!blockIsValid[wrapIndex(i + j)] || !seqIsValid[wrapIndex(i + j)]) {
                        isIndexOk = false;
                        break;
                    }
                }

                if (isIndexOk) {
                    assignmentArray[i] = this.assignments[i];
                } else {
                    assignmentArray[i] = -1;
                    unassignedCount[i%SetUp.getInstance().getLengthOfSchedule()]++;
                }
            }
            //check openness of array
            isOpenEnough=true;
            for(int i=0;i<unassignedCount.length;i++){
                if(unassignedCount[i]>0&&unassignedCount[i]<MIN_UNASSIGNED){
                    isOpenEnough=false;
                    break;
                }
            }
            System.out.println();
            range++;
        } while (!isOpenEnough);
        System.out.println("created assignment array with range: "+(range-1));
        return assignmentArray;
    }

    private int wrapIndex(int index) {
        if (index < 0) {
            index += n;
        }
        index = index % n;

        return index;
    }

    public boolean[] getBlockIsValid() {
        return blockIsValid;
    }

    public void setBlockIsValid(boolean[] blockIsValid) {
        this.blockIsValid = blockIsValid;
    }

    public boolean[] getSeqIsValid() {
        return seqIsValid;
    }

    public void setSeqIsValid(boolean[] seqIsValid) {
        this.seqIsValid = seqIsValid;
    }

    public int getSeqError() {
        return seqError;
    }

    public void setSeqError(int seqError) {
        this.seqError = seqError;
    }

    public int getBlockError() {
        return blockError;
    }

    public void setBlockError(int blockError) {
        this.blockError = blockError;
    }

}
